﻿using Microsoft.Owin;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace Acadsoc.Middleware
{
    public class TestMiddleware : OwinMiddleware
    {
        private CustomAuthenticationOptions Options;
        /// <summary>
        /// 构造函数，第一个参数必须为 OwinMiddleware对象 ;第一个参数是固定的，后边还可以添加自定义的其它参数
        /// </summary>
        /// <param name="next">下一个中间件</param>
        public TestMiddleware(OwinMiddleware next, CustomAuthenticationOptions options)
            : base(next)
        {
            Options = options;
        }


        /// <summary>
        /// 处理用户请求的具体方法，该方法是必须的
        /// </summary>
        /// <param name="c">OwinContext对象</param>
        /// <returns></returns>
        public override Task Invoke(IOwinContext context)
        {
            string url = context.Request.Uri.AbsoluteUri;
            string ssoSiteUrl = Options.Authority + "/Authorize/Index";
            string ssologoutSiteUrl = Options.Authority + "/Authorize/Logout";
           
            var cookie = GetCookie(context, Constants.AuthCookieKey);
            UserSSoModel userSSoModel = null;
            //登出处理
            if (url.ToLower().IndexOf(Options.ClientSignOutUrl.ToLower()) > 0)
            {
              
                if (cookie != null)
                {
                    string currenttoken = cookie.Value;
                    RemoveCookie(context, cookie.Name);
                    context.Response.Redirect(string.Format("{0}?{1}={2}&{3}={4}", ssologoutSiteUrl, "token", currenttoken, "returnUrl", GetUrlReferrer(context)));
                    return GetCompletedTask();
                }

                return Next.Invoke(context);

            }
            if (!string.IsNullOrEmpty(context.Request.Query["Token"]))
            {
                if(!ValidateState(context))
                {
                    context.Response.Write("非法登录");
                    return GetCompletedTask();
                }
                
                try
                {
                    IDictionary<string, object> payload = JWTHelper.Decode(context.Request.Query["Token"].ToString(), Options.TokenSecret);
                    string token = payload["token"].ToString();
                    userSSoModel = SSoHelper.GetUserByToken(Options.Authority,token);
                    if (userSSoModel != null)
                    {
                        AddCookie(context, Constants.AuthCookieKey, token);
                        url = HttpQueryStringHelper.RemoveParm(url, "State");
                        url = HttpQueryStringHelper.RemoveParm(url, "Token");

                        context.Response.Redirect(url);
                        return GetCompletedTask();
                    }
                }
                catch(Exception ex)
                {
                    context.Response.Write("token验证失败");
                    return GetCompletedTask();
                }
            }

            if (cookie != null)
            {

                userSSoModel = SSoHelper.GetUserByToken(Options.Authority,cookie.Value);
                if (userSSoModel != null)
                {
                    context.Request.User = SSoHelper.GenerateCustomPrincipal(userSSoModel.uid);
                    return Next.Invoke(context);

                }
                else
                {

                    RemoveCookie(context, cookie.Name);
                    string returnurl = HttpUtility.UrlEncode(context.Request.Uri.AbsoluteUri);
                    context.Response.Redirect(string.Format("{0}?{1}={2}", ssoSiteUrl, "ReturnUrl", returnurl));
                    return GetCompletedTask();
                }

            }
            else
            {
                string returnurl = HttpUtility.UrlEncode(context.Request.Uri.AbsoluteUri);
                context.Response.Redirect(string.Format("{0}?{1}={2}", ssoSiteUrl, "ReturnUrl", returnurl));
                return GetCompletedTask();
            }
        }

        private Task GetCompletedTask()
        {
            var tcs = new TaskCompletionSource<object>();
            tcs.TrySetResult(null);
            return tcs.Task;
        }

        private void RemoveCookie(IOwinContext context,string cookiename)
        {
            var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            httpContext.Response.Cookies.Remove(cookiename);
            HttpCookie myCookie = new HttpCookie(cookiename);
            myCookie.Expires = DateTime.Now.AddDays(-1d);
            httpContext.Response.Cookies.Add(myCookie);
        }

        private HttpCookie GetCookie(IOwinContext context, string cookiename)
        {
            var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            var cookie = httpContext.Request.Cookies[Constants.AuthCookieKey];
            return cookie;
        }

        private void AddCookie(IOwinContext context, string cookiename,string cookievalue)
        {
            var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            var cookie = new HttpCookie(cookiename);
            cookie.Value = cookievalue;
            if (httpContext != null)
            {
                httpContext.Response.Cookies.Add(cookie);
            }
        }

        private string GetUrlReferrer(IOwinContext context)
        {
            var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            return httpContext.Request.UrlReferrer.AbsoluteUri;
        }

        private bool ValidateState(IOwinContext context)
        {
            string querystate= context.Request.Query[Constants.QueryState];
            var cookie = GetCookie(context, Constants.TemplateCookieKey);
            RemoveCookie(context, Constants.TemplateCookieKey);
            if (string.IsNullOrEmpty(querystate))
            {
                return false;
            }
            if(cookie==null)
            {
                return false;
            }

            if(querystate==cookie.Value)
            {
                return true;
            }
            else
            {
                return false;
            }


        }

        private void RedirectSSOAction(IOwinContext context,string ssoSiteUrl)
        {
            var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
            //httpContext.Response.Cookies.Remove(Constants.TemplateCookieKey);
            var cookie = new HttpCookie(Constants.TemplateCookieKey);
            cookie.Value = Guid.NewGuid().ToString("N");
            if (httpContext != null)
            {
                httpContext.Response.Cookies.Add(cookie);
            }
            string returnurl = HttpUtility.UrlEncode(context.Request.Uri.AbsoluteUri);
            context.Response.Redirect(string.Format("{0}?{1}={2}&{3}={4}", ssoSiteUrl, "ReturnUrl", returnurl, Constants.QueryState, cookie.Value));
        }





    }
}
